package cn.chiship.framework.business.core.aspect;

import cn.chiship.framework.common.annotation.SystemOptionAnnotation;
import cn.chiship.framework.common.constants.CommonConstants;
import cn.chiship.framework.common.pojo.dto.SystemOptionLogDto;
import cn.chiship.framework.common.util.FrameworkUtil2;
import cn.chiship.framework.upms.biz.system.entity.UpmsSystemOptionLog;
import cn.chiship.framework.upms.biz.system.service.UpmsSystemOptionLogService;
import cn.chiship.sdk.cache.service.UserCacheService;
import cn.chiship.sdk.cache.vo.CacheUserVO;
import cn.chiship.sdk.core.util.http.CustomRequestWrapper;
import cn.chiship.sdk.core.util.http.RequestUtil;
import cn.chiship.sdk.core.util.ip.IpUtils;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 日志记录AOP实现
 *
 * @author lijian
 */
@Aspect
@Component
public class LogAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);
    private static final String CONTENT_TYPE_APPLICATION_JSON = "application/json";
    private static final String STRING_METHOD_NAME = "methodName";
    @Resource
    private UpmsSystemOptionLogService upmsSystemOptionLogService;
    @Resource
    private UserCacheService userCacheService;

    /**
     * 开始时间
     */
    private long startTime = 0L;
    /**
     * 结束时间
     */
    private long endTime = 0L;


    @Before("execution(* *..controller..*.*(..))")
    public void doBeforeInServiceLayer(JoinPoint joinPoint) {
        LOGGER.debug("doBeforeInServiceLayer");
        startTime = System.currentTimeMillis();
    }

    @After("execution(* *..controller..*.*(..))")
    public void doAfterInServiceLayer(JoinPoint joinPoint) {
        LOGGER.debug("doAfterInServiceLayer");
    }

    @Around("execution(* *..controller..*.*(..))")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        /**
         * 获取request
         */
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        /**
         * 从注解中获取操作名称、获取响应结果
         */
        Object result = pjp.proceed();
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        SystemOptionAnnotation systemOption = method.getAnnotation(SystemOptionAnnotation.class);
        endTime = System.currentTimeMillis();
        LOGGER.debug("doAround>>>,耗时：{}", endTime - startTime);

        saveLog(request, result, systemOption);


        return result;
    }

    void saveLog(HttpServletRequest request, Object result, SystemOptionAnnotation systemOption) {
        UpmsSystemOptionLog upmsSystemOptionLog = new UpmsSystemOptionLog();
        upmsSystemOptionLog.setBasePath(RequestUtil.getBasePath(request));
        upmsSystemOptionLog.setIp(IpUtils.getIpAddr(request));
        upmsSystemOptionLog.setRequestType(request.getMethod());
        upmsSystemOptionLog.setResult(JSON.toJSONString(result));
        upmsSystemOptionLog.setSpendTime((int) (endTime - startTime));
        upmsSystemOptionLog.setStartTime(startTime);
        upmsSystemOptionLog.setUri(request.getRequestURI());
        upmsSystemOptionLog.setUserAgent(request.getHeader("User-Agent"));
        try {
            if (CommonConstants.HTTP_REQUEST_TYPE_GET.equalsIgnoreCase(request.getMethod())) {
                upmsSystemOptionLog.setParameter(request.getQueryString());
            } else {
                String contentType = request.getHeader("Content-Type");
                if (contentType.indexOf(CONTENT_TYPE_APPLICATION_JSON) >= 0) {
                    CustomRequestWrapper requestWrapper = new CustomRequestWrapper(request);
                    upmsSystemOptionLog.setParameter(requestWrapper.getBody());
                } else {
                    upmsSystemOptionLog.setParameter(JSON.toJSONString(request.getParameterMap()));
                }

            }
            CacheUserVO userVO = userCacheService.getUser();
            if (userVO != null) {
                upmsSystemOptionLog.setUserId(userVO.getId().toString());
                upmsSystemOptionLog.setUserName(userVO.getUsername());
                upmsSystemOptionLog.setRealName(userVO.getRealName());
            }
        } catch (Exception e) {
        }
        if (request.getAttribute(STRING_METHOD_NAME) != null) {
            upmsSystemOptionLog.setMethod(request.getAttribute(STRING_METHOD_NAME).toString());
        }
        if (null != systemOption) {
            upmsSystemOptionLog.setDescription(systemOption.describe());
            upmsSystemOptionLog.setOptionType(systemOption.option().getCode());
            upmsSystemOptionLog.setSystemName(systemOption.systemName());
            upmsSystemOptionLog.setOperatorType(systemOption.operatorType().toString());
            SystemOptionLogDto systemOptionLogDto = new SystemOptionLogDto();
            BeanUtils.copyProperties(upmsSystemOptionLog, systemOptionLogDto);
            FrameworkUtil2.formatInfoMessage(systemOptionLogDto);
            if (FrameworkUtil2.getGlobalProperties().isEnableLogInterception()) {
                upmsSystemOptionLogService.insertSelective(upmsSystemOptionLog);
            }
        }

    }

}
